package com.yuandian.customer.perception.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuandian.api.customer_perception.po.VisitReportParams;
import com.yuandian.api.customer_perception.vo.ReportInfo;
import com.yuandian.api.customer_perception.vo.UserVisitDetailVo;
import com.yuandian.api.customer_perception.vo.UserVisitOverrideVo;
import com.yuandian.api.customer_perception.vo.VisitOverrideVo;
import com.yuandian.api.management.feign.RemoteOptionService;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.customer.perception.mapper.VisitReportMapper;
import com.yuandian.customer.perception.service.VisitReportService;
import com.yuandian.enums.TableNameEnum;
import com.yuandian.utils.*;
import com.yuandian.utils.poi.ExcelTitleUtils;
import com.yuandian.utils.poi.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author liXin
 * @description 报表访问报表
 * @date 2022/5/23
 */
@Slf4j
@Service
public class VisitReportServiceImpl implements VisitReportService {

    @Autowired
	VisitReportMapper visitReportMapper;

    @Autowired
	RemoteOptionService searchOptionService;


    /**
     * 报表页面访问总览
     *
     * @param params
     * @return
     */
    @Override
    public R visitOverride(VisitReportParams params) {

        //分页
        List<String> tableNameList = new ArrayList<>();
		tableNameList.add(TableNameEnum.ADS_BUSI_REPORT_URL_STAT_M.getName());
        IPage<VisitOverrideVo> page =  visitReportMapper.visitOverride(new Page<>(params.getPageNum(), params.getPageSize()), params, tableNameList);
        return R.ok(new PageDataInfo(page));
    }

    /**
     * 用户访问概览
     *
     * @param params
     * @return
     */
    @Override
    public R userVisitOverride(VisitReportParams params) {
        List<String> tableNameList = Collections.singletonList(TableNameEnum.ADS_BUSI_REPORT_URL_STAT_M.getName());
        IPage<UserVisitOverrideVo> page = visitReportMapper.userVisitOverride(new Page<>(params.getPageNum(), params.getPageSize()), params, tableNameList);
        return R.ok(new PageDataInfo(page));
    }

    /**
     * 用户访问明细
     *
     * @param params
     * @return
     */
    @Override
    public R userVisitDetail(VisitReportParams params) {

		List<String> tableNameList = Collections.singletonList(TableNameEnum.ADS_BUSI_REPORT_URL_STAT_M.getName());
        List<UserVisitOverrideVo> page1 = visitReportMapper.getDetailKeys(params, tableNameList);
        List<String> detailKeys = page1.stream().map(UserVisitOverrideVo::getDetailKey).collect(Collectors.toList());

        List<String> detailTableNames = Collections.singletonList(TableNameEnum.ADS_BUSI_REPORT_URL_DETAIL_M.getName());
        IPage<UserVisitDetailVo> page = visitReportMapper.userVisitDetail(new Page<>(params.getPageNum(), params.getPageSize()), params, detailTableNames, detailKeys);
        return R.ok(new PageDataInfo(page));

    }

    /**
     * 查询用户详情（下载使用）
     * @param params
     * @return
     */
    public R userVisitDetailByDown(VisitReportParams params) {

        List<String> tableNameList = new ArrayList<>();
		tableNameList.add("busi_report_url_detail_m_");
        String[] detailKeys = null;
        if (params.getDetailKeys() != null) {
            detailKeys = params.getDetailKeys().split(",");
        }
        IPage<UserVisitDetailVo> page = visitReportMapper.userVisitDetailByDown(new Page<>(params.getPageNum(), params.getPageSize()), params, tableNameList, detailKeys);
        return R.ok(new PageDataInfo(page));

    }

    /**
     * 下拉菜单框
     *
     * @param params
     * @return
     */
    @Override
    public R getReportInfo(VisitReportParams params) {
        // 如果不要求分页,则查询全部数据
        if (params.getPageNum() == 0  || params.getPageNum() == 0) {
            params.setPageNum(1);
            params.setPageSize(-1);
        }
        IPage<ReportInfo> page = visitReportMapper.getReportInfo(new Page<>(params.getPageNum(), params.getPageSize()), params);
        return R.ok(new PageDataInfo(page));
    }


    /**
     *下载所有的数据
     * @param params
     * @param response
     */
    @Override
    public void exportAllData(VisitReportParams params, HttpServletResponse response) {
        long startTime = System.currentTimeMillis();

        // 定义导出结果集（数据总览表、用户总览表、用户明细表）
        List<VisitOverrideVo> overrideVoList = new ArrayList<>();
        List<UserVisitOverrideVo> userOverrideVoList = new ArrayList<>();
        List<UserVisitDetailVo> userDetailVoList = new ArrayList<>();

        // 初始化 sheet 下标
        Integer sheetNo = 0;

        ExcelWriter excelWriter = null;
        try {
            // 实例化 ExcelWriter 对象
            excelWriter = EasyExcel.write(response.getOutputStream())
                    .registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
                    .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 30, (short) 20))
                    .build();

            // 1.进行数据总览表Sheet导出
            sheetNo = performAllDataDownload(overrideVoList, sheetNo, excelWriter, params);
            // 2.进行用户总览表Sheet导出
            sheetNo = performUserOverrideDataDownload(userOverrideVoList, sheetNo, excelWriter, params);
            // 3.进行用户明细表Sheet导出
            performUserDetailDataDownload(userDetailVoList, sheetNo, excelWriter, params);

            // 返回文件流
            ExcelUtil.writeExcel("访问报表下载", response);

        } catch (Exception e) {
            log.error("访问报表下载异常!", e);
        } finally {
            if (excelWriter != null) {
                try {
                    response.getOutputStream().flush();
                    excelWriter.finish();
                    response.getOutputStream().close();
                }catch (Exception e) {
                    log.error("IO流关闭异常： " + e.getMessage());
                }
            }
        }
        log.info("访问报表导出成功,耗时: {}ms", (System.currentTimeMillis() - startTime));
    }

    /**
     * 进行用户明细表Sheet导出
     * @param userDetailVoList
     * @param sheetNo
     * @param excelWriter
     * @param params
     */
    private void performUserDetailDataDownload(List<UserVisitDetailVo> userDetailVoList,
                                               Integer sheetNo,
                                               ExcelWriter excelWriter,
                                               VisitReportParams params) {

        try {
            // 初始化Excel标题, 序号
            long indexNo = 1;
            String sheetName = "用户访问明细";
            String formTitleName = getFormTitleName(sheetName, params);
            List<List<String>> headList = new ArrayList<>();
            List<String> displayFields = new ArrayList<>();
            displayFields.addAll(Arrays.asList("序号 ", "系统名称", "报表名称", "报表cptURL", "用户ID ", "用户名", "处理时长", "开始时间", "结束时间"));
            ExcelUtil.executeUpdateHeader(displayFields, headList, formTitleName);

            // 初始化查询对象
            params.setIsQueryAllOperator(1);
            // 先查询第一页数据
            params.setPageNum(1);
            params.setPageSize(500);
            R result = userVisitDetailByDown(params);
            PageDataInfo pageDataInfo = BeanUtils.cast(result.getData());
            List<UserVisitDetailVo> dataList = BeanUtils.cast(pageDataInfo.getData());

            // 没数据则进行空表导出
            if (!ListUtils.isNotNull(dataList)) {
                ExcelUtil.writeOnly(excelWriter, dataList, headList, sheetNo++, sheetName, null);
            }

            // 加入待导出集合
            userDetailVoList.addAll(dataList);
            dataList.clear();

            // 计算总页数，后面要进行分页查询
            long totality = pageDataInfo.getTotal();
            long totalPage = (totality / 500) + (totality % 500 == 0 ? 0 : 1);

            // 分页请求数据(i = 2 是因为上面已经请求了第一页的数据)
            for (long i = 2; i <= totalPage; i++) {
                params.setPageNum(i);
                result = userVisitDetailByDown(params);
                pageDataInfo = BeanUtils.cast(result.getData());
                dataList = BeanUtils.cast(pageDataInfo.getData());
                userDetailVoList.addAll(dataList);
                dataList.clear();

                // 若达到sheet最大值则进行写入： 132 = （sheet允许的最大行数 / 每次查询的条数pageSize）
                if (i % 132 == 0) {
                    for (UserVisitDetailVo vo : userDetailVoList) {
                        // 更新序号
                        vo.setId(indexNo++);

                        // 处理时长
                        String dealTime = StringUtils.isEmpty(vo.getDealTime()) ? "0" : vo.getDealTime();
                        vo.setDealTime(DateTool.getMinSecond(getDouble(Double.parseDouble(dealTime) / 1000)));
                    }
                    ExcelUtil.writeOnly(excelWriter, userDetailVoList, headList, sheetNo++, sheetName, null);
                    userDetailVoList.clear();
                }
            }

            // 对剩余的数据进行写入
            if (userDetailVoList != null && userDetailVoList.size() > 0) {
                for (UserVisitDetailVo vo : userDetailVoList) {
                    // 更新序号
                    vo.setId(indexNo++);

                    // 处理时长
                    String dealTime = StringUtils.isEmpty(vo.getDealTime()) ? "0" : vo.getDealTime();
                    vo.setDealTime(DateTool.getMinSecond(getDouble(Double.parseDouble(dealTime) / 1000)));
                }

                ExcelUtil.writeOnly(excelWriter, userDetailVoList, headList, sheetNo++, sheetName, null);
                userDetailVoList.clear();
            }

        }catch (Exception e) {
            log.error("用户操作明细导出报错 ", e);
        }
    }

    public static Double getDouble(Double allTime) {
        if (allTime == null) {
            return 0d;
        }
        return new BigDecimal(allTime).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 进行用户总览表Sheet导出
     * @param userOverrideVoList
     * @param sheetNo
     * @param excelWriter
     * @param params
     * @return
     */
    private Integer performUserOverrideDataDownload(List<UserVisitOverrideVo> userOverrideVoList,
                                                    Integer sheetNo,
                                                    ExcelWriter excelWriter,
                                                    VisitReportParams params) {

        try {
            // 初始化Excel标题, 序号
            long indexNo = 1;
            String sheetName = "用户访问概览";
            String formTitleName = getFormTitleName(sheetName, params);
            List<List<String>> headList = new ArrayList<>();
            List<String> displayFields = new ArrayList<>();
            displayFields.addAll(Arrays.asList("序号 ", "系统名称", "报表名称", "报表cptURL",  "用户ID ", "用户名 ", "访问量"));
            ExcelUtil.executeUpdateHeader(displayFields, headList, formTitleName);

            // 先查询第一页数据
            params.setIsQueryAllOperator(1);
            params.setPageNum(1);
            params.setPageSize(500);
            R result = userVisitOverride(params);
            PageDataInfo pageDataInfo = BeanUtils.cast(result.getData());
            List<UserVisitOverrideVo> dataList = BeanUtils.cast(pageDataInfo.getData());

            // 没数据则进行空表导出
            if (!ListUtils.isNotNull(dataList)) {
                ExcelUtil.writeOnly(excelWriter, dataList, headList, sheetNo++, sheetName, null);
                return sheetNo;
            }

            // 加入待导出集合
            userOverrideVoList.addAll(dataList);
            dataList.clear();

            // 计算总页数，后面要进行分页查询
            long totality = pageDataInfo.getTotal();
            long totalPage = (totality / 500) + (totality % 500 == 0 ? 0 : 1);

            // 分页请求数据(i = 2 是因为上面已经请求了第一页的数据)
            for (long i = 2; i <= totalPage; i++) {
                params.setPageNum(i);
                result = userVisitOverride(params);
                pageDataInfo = BeanUtils.cast(result.getData());
                dataList = BeanUtils.cast(pageDataInfo.getData());
                userOverrideVoList.addAll(dataList);
                dataList.clear();

                // 若达到sheet最大值则进行写入： 132 = （sheet允许的最大行数 / 每次查询的条数pageSize）
                if (i % 132 == 0) {
                    for (UserVisitOverrideVo vo : userOverrideVoList) {
                        // 更新序号
                        vo.setId(indexNo++);
                    }
                    ExcelUtil.writeOnly(excelWriter, userOverrideVoList, headList, sheetNo++, sheetName, null);
                    userOverrideVoList.clear();
                }
            }

            // 对剩余的数据进行写入
            if (userOverrideVoList != null && userOverrideVoList.size() > 0) {
                for (UserVisitOverrideVo vo : userOverrideVoList) {
                    // 更新序号
                    vo.setId(indexNo++);
                }

                ExcelUtil.writeOnly(excelWriter, userOverrideVoList, headList, sheetNo++, sheetName, null);
                userOverrideVoList.clear();
            }
        }catch (Exception e) {
            log.error("用户访问概览导出报错 ", e);
        }

        return sheetNo;
    }

    /**
     * 进行数据总览表Sheet导出
     * @param overrideVoList
     * @param sheetNo
     * @param excelWriter
     * @param params
     * @return
     */
    private Integer performAllDataDownload(List<VisitOverrideVo> overrideVoList,
                                           Integer sheetNo,
                                           ExcelWriter excelWriter,
                                           VisitReportParams params) {
        try {
            // 初始化Excel标题, 序号
            long indexNo = 1;
            String sheetName = "报表页面访问总览";
            String formTitleName = getFormTitleName(sheetName, params);
            List<List<String>> headList = new ArrayList<>();
            List<String> displayFields = new ArrayList<>();
            displayFields.addAll(Arrays.asList("序号", "系统名称", "报表名称", "报表cptURL", "访问量", "用户数"));
            ExcelUtil.executeUpdateHeader(displayFields, headList, formTitleName);

            // 先查询第一页数据
            params.setPageNum(1);
            params.setPageSize(500);
            R result = visitOverride(params);
            PageDataInfo pageDataInfo = BeanUtils.cast(result.getData());
            List<VisitOverrideVo> dataList = BeanUtils.cast(pageDataInfo.getData());

            // 没数据则进行空表导出
            if (!ListUtils.isNotNull(dataList)) {
                ExcelUtil.writeOnly(excelWriter, dataList, headList, sheetNo++, sheetName, null);
                return sheetNo;
            }
            // 加入待导出集合
            overrideVoList.addAll(dataList);
            dataList.clear();

            // 计算总页数，后面要进行分页查询
            long totality = pageDataInfo.getTotal();
            long totalPage = (totality / 500) + (totality % 500 == 0 ? 0 : 1);

            // 分页请求数据(i = 2 是因为上面已经请求了第一页的数据)
            for (long i = 2; i <= totalPage; i++) {
                params.setPageNum(i);
                result = visitOverride(params);
                pageDataInfo = BeanUtils.cast(result.getData());
                dataList = BeanUtils.cast(pageDataInfo.getData());
                overrideVoList.addAll(dataList);
                dataList.clear();

                // 若达到sheet最大值则进行写入： 132 = （sheet允许的最大行数(66000) / 每次查询的条数pageSize）
                if (i % 132 == 0) {
                    for (VisitOverrideVo vo : overrideVoList) {
                        // 更新序号
                        vo.setId(indexNo++);
                    }
                    ExcelUtil.writeOnly(excelWriter, overrideVoList, headList, sheetNo++, sheetName, null);
                    overrideVoList.clear();
                }
            }

            // 对剩余的数据进行写入
            if (overrideVoList != null && overrideVoList.size() > 0) {
                for (VisitOverrideVo vo : overrideVoList) {
                    // 更新序号
                    vo.setId(indexNo++);
                }

                ExcelUtil.writeOnly(excelWriter, overrideVoList, headList, sheetNo++, sheetName, null);
                overrideVoList.clear();
            }
        }catch (Exception e) {
            log.error("报表页面访问总览报错", e);
        }

        return sheetNo;
    }

    /**
     * 获取Excel大标题名称
     * @param title
     * @param params
     * @return
     */
    private String getFormTitleName(String title, VisitReportParams params) {
        List<String> titleParams = new ArrayList<>();
        titleParams.add(title);
        titleParams.add(params.getSystemName());
        String formTitleName = ExcelTitleUtils.formTitleName(titleParams, params.getStartTime(), params.getEndTime());
        return formTitleName;
    }
}
